#include "stdafx.h"
#include "ParticleEmitter.h"
#include "ParticleSystem.h"
#include "Particle.h"
#include "ParticleEffector.h"
#include "..\..\EdgeGraphics\Material.h"
#include "..\..\EdgeGraphics\GraphicsManager.h"
#include "..\..\EdgeMath\VectorHelper.h"
#include "..\..\EdgeGraphics\Camera.h"

ParticleEmitter::ParticleEmitter(void)
{
	gShaderConstBuffer = new ConstantBuffer<VRAM>(&toShader, { SHADER_INDEX_GEOMETRY_SHADER, 0 });
}
ParticleEmitter::~ParticleEmitter(void)
{
	delete texture;
	delete gShaderConstBuffer;
}

#pragma region Randomize functions
float randomize(float min, float max)
{
	float range = max - min;
	int value = rand() % 1000;

	return min + (float(value) / 1000.f) * range;
}

Vector3 randomize(Vector3& min, Vector3& max)
{
	Vector3 outval;
	
	outval.x = randomize(min.x, max.x);
	outval.y = randomize(min.y, max.y);
	outval.z = randomize(min.z, max.z);

	return outval;
}

Vector4 randomize(Vector4& min, Vector4& max)
{
	Vector4 outval;

	outval.x = randomize(min.x, max.x);
	outval.y = randomize(min.y, max.y);
	outval.z = randomize(min.z, max.z);
	outval.w = randomize(min.z, max.w);

	return outval;
}
#pragma endregion

void ParticleEmitter::Emit(unsigned int numParticles)
{
	for (unsigned int i = 0, ii = 0; i < MAX_PARTICLES && ii < numParticles; i++)
	{
		// find a non-living particle and deploy it
		if (!particles[i].isAlive)
		{
			Particle* p = &particles[i];
			p->acceleration = randomize(min_acceleration, max_acceleration);
			p->velocity = randomize(min_velocity, max_velocity);
			Vector3 topLeftFront = Vector3(region.left, region.top, region.front);
			Vector3 bottomRightBack = Vector3(region.right, region.bottom, region.back);
			p->position = randomize(topLeftFront, bottomRightBack);
			p->end_alpha = randomize(min_endAlpha, max_endAlpha);
			p->start_alpha = randomize(min_startAlpha, max_startAlpha);
			p->start_size = randomize(min_startSize, max_startSize);
			p->end_size = randomize(min_endSize, max_endSize);
			p->max_lifetime = p->lifetime = randomize(min_lifetime, max_lifetime);
			p->rotation = randomize(min_rotation, max_rotation);
			p->rotation_speed = randomize(min_rotationSpeed, max_rotationSpeed);
			p->start_color = randomize(min_startColor, max_startColor);
			p->end_color = randomize(min_endColor, max_endColor);
			p->texture = texture;

			p->isAlive = true;
			ii++;
		}		
	}
}

void ParticleEmitter::Update(float dt)
{
	// only on the first update call ////////////////////////////
	static bool first = true;
	if (first)
	{
		emit_timer = emit_frequency;
		first = false;
	}
	//////////////////////////////////////////////////////////////

	// update timed burst
	if (emit_frequency != 0)
	{
		emit_timer -= dt;
		if (emit_timer < 0)
			Emit(emit_burst);

		// reset timer
		emit_timer = emit_frequency;
	}

	// update particles
	for (int i = 0; i < MAX_PARTICLES; i++)
		if (particles[i].isAlive)
		{
			particles[i].Update(dt);
			if (particles[i].lifetime < 0.f)
				particles[i].isAlive = false;
			// update particles relitive to effectors
			for (unsigned int i = 0; i < parent->effectors.size(); i++)
				parent->effectors[i]->Effect(&particles[i]);
		}
}

void ParticleEmitter::Draw(void)
{
	// draw particles
	for (int i = 0; i < MAX_PARTICLES; i++)
		if (particles[i].isAlive)
		{
			toShader.world = VectorHelper::Matricies::CreateRotationZ(particles[i].rotation) * VectorHelper::Matricies::CreateTranslation(particles[i].position);
			toShader.view = Camera::GetInstance()->getView();
			toShader.proj = Camera::GetInstance()->getProj();

			toShader.alpha = particles[i].getCurrentAlpha();
			toShader.scale = particles[i].getCurrentSize();
			toShader.color = particles[i].getCurrentColor();

			gShaderConstBuffer->Bind();

			GraphicsManager::GetInstance()->Draw(&particles[i]);
		}
}